package com.aipanda.entity;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.Digits;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;

import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;

import com.aipanda.pojo.Setting;
import com.aipanda.util.SettingUtils;

/**
 * 优惠券类
 * @param point  积分兑换数
 * @param priceValue  价格值，是+-x/这个价格数
 * @param isExchange 是否允许积分兑换
 * @author wanyuxiang
 *
 */
@Entity
@Table(name = "aipanda_coupon")
public class Coupon extends BaseEntity {
	private static final long serialVersionUID = -7907808728349149722L;
	private String name;
	private String prefix;
	private Date beginDate;
	private Date endDate;
	private BigDecimal startPrice;
	private BigDecimal endPrice;
	private Boolean isEnabled;
	private Boolean isExchange;
	private Integer point;
	private Operator operator;
	private BigDecimal priceValue;
	private String introduction;
	private Set<CouponCode> couponCodes = new HashSet<CouponCode>();
	private Set<Promotion> promotions = new HashSet<Promotion>();
	private List<Order> orders = new ArrayList<Order>();

	public enum Operator {
		add, subtract, multiply, divide;
	}

	@NotEmpty
	@Length(max = 255)
	@Column(nullable = false)
	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@NotEmpty
	@Length(max = 255)
	@Column(nullable = false)
	public String getPrefix() {
		return this.prefix;
	}

	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}
	@Column(name="begin_date",nullable = false)
	public Date getBeginDate() {
		return this.beginDate;
	}

	public void setBeginDate(Date beginDate) {
		this.beginDate = beginDate;
	}
	@Column(name="end_date")
	public Date getEndDate() {
		return this.endDate;
	}

	public void setEndDate(Date endDate) {
		this.endDate = endDate;
	}

	@Min(0L)
	@Digits(integer = 15, fraction = 6)
	@Column(name="start_price",precision = 21, scale = 6)
	public BigDecimal getStartPrice() {
		return this.startPrice;
	}

	public void setStartPrice(BigDecimal startPrice) {
		this.startPrice = startPrice;
	}

	@Min(0L)
	@Digits(integer = 15, fraction = 6)
	@Column(name="end_price",precision = 21, scale = 6)
	public BigDecimal getEndPrice() {
		return this.endPrice;
	}

	public void setEndPrice(BigDecimal endPrice) {
		this.endPrice = endPrice;
	}

	@NotNull
	@Column(name="is_enabled",nullable = false)
	public Boolean getIsEnabled() {
		return this.isEnabled;
	}

	public void setIsEnabled(Boolean isEnabled) {
		this.isEnabled = isEnabled;
	}

	@NotNull
	@Column(name="is_exchange",nullable = false)
	public Boolean getIsExchange() {
		return this.isExchange;
	}

	public void setIsExchange(Boolean isExchange) {
		this.isExchange = isExchange;
	}

	@Min(0L)
	public Integer getPoint() {
		return this.point;
	}

	public void setPoint(Integer point) {
		this.point = point;
	}

	@NotNull
	@Column(name="price_operator",nullable = false)
	public Operator getPriceOperator() {
		return this.operator;
	}

	public void setPriceOperator(Operator priceOperator) {
		this.operator = priceOperator;
	}

	@Digits(integer = 15, fraction = 6)
	@Column(name="price_value",precision = 21, scale = 6)
	public BigDecimal getPriceValue() {
		return this.priceValue;
	}

	public void setPriceValue(BigDecimal priceValue) {
		this.priceValue = priceValue;
	}

	@Lob
	public String getIntroduction() {
		return this.introduction;
	}

	public void setIntroduction(String introduction) {
		this.introduction = introduction;
	}

	@OneToMany(mappedBy = "coupon", fetch = FetchType.LAZY, cascade = {CascadeType.REMOVE })
	public Set<CouponCode> getCouponCodes() {
		return this.couponCodes;
	}

	public void setCouponCodes(Set<CouponCode> couponCodes) {
		this.couponCodes = couponCodes;
	}

	@ManyToMany(mappedBy = "coupons", fetch = FetchType.LAZY)
	public Set<Promotion> getPromotions() {
		return this.promotions;
	}

	public void setPromotions(Set<Promotion> promotions) {
		this.promotions = promotions;
	}

	@ManyToMany(mappedBy = "coupons", fetch = FetchType.LAZY)
	public List<Order> getOrders() {
		return this.orders;
	}

	public void setOrders(List<Order> orders) {
		this.orders = orders;
	}

	@Transient
	public boolean hasBegun() {
		return (getBeginDate() == null) || (new Date().after(getBeginDate()));
	}

	@Transient
	public boolean hasExpired() {
		return (getEndDate() != null) && (new Date().after(getEndDate()));
	}

	@Transient
	public BigDecimal calculatePrice(BigDecimal price) {
		if (price != null && getPriceOperator() != null&& (getPriceValue() != null)) {
			BigDecimal bigDecimal = null;
			Setting setting = SettingUtils.get();
			if (getPriceOperator() == Operator.add){
				bigDecimal = price.add(getPriceValue());
			}else if (getPriceOperator() == Operator.subtract){
				bigDecimal = price.subtract(getPriceValue());
			}else if (getPriceOperator() == Operator.multiply){
				bigDecimal = price.multiply(getPriceValue());
			}else{
				bigDecimal = price.divide(getPriceValue());
			}
			bigDecimal = setting.setPriceScale(bigDecimal);
			return bigDecimal.compareTo(new BigDecimal(0)) > 0 ? bigDecimal: new BigDecimal(0);
		}
		return price;
	}

	public Coupon preRemove(Coupon coupon) {
		
		Set<Promotion> currentPromotions = coupon.getPromotions();
		
		if (currentPromotions != null) {
			Iterator<Promotion> promotions = currentPromotions.iterator();
			while (promotions.hasNext()) {
				Promotion	promotion = promotions.next();
				promotion.getCoupons().remove(this);
			}
		}
		
		List<Order> orders = coupon.getOrders();
		if (orders != null) {
			Iterator<Order> currentOrders = orders.iterator();
			while (currentOrders.hasNext()) {
				Order order = currentOrders.next();
				order.getCoupons().remove(this);
			}
		}
		return coupon;
	}
}
